/*
 * Created on 2005-3-23
 *
 */
package com.hd123.rumba.impex;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

import net.sf.hibernate.Transaction;

import org.apache.log4j.Logger;

import com.hd123.rumba.exception.ParameterException;
import com.hd123.rumba.runtime.Manager;
import com.hd123.rumba.user.IUser;
import com.hd123.rumba.util.StringUtil;

/**
 * 约定导入导出执行者的类为"CLASSPACKAGE.对象名称(小写).对象名称Impex"
 * 
 * @author caili
 */
public class ImpexXml extends Manager {
  private final static String LEAD = "objectName=\"";
  private final static String END = "\"";
  private final static String LEAD2 = "<objectName>";
  private final static String END2 = "<";
  private final static String CLASSPACKAGE = "com.hd123.rumba.impex.";
  private final static String CLASSSUFFIX = "Impex";

  /**
   * @param file
   *          可以是一个zip文件
   * @return vector of ImpexStatus
   * @throws Exception
   */
  public Vector doImport(File file, IUser user) throws Exception {
    Vector v = new Vector();

    // is zip file?
    ZipFile zip = null;
    try {
      zip = new ZipFile(file);
    } catch (ZipException e) {
      // 不是zip文件
    }

    String fileName = StringUtil.extractFileName(file.getName());
    if (zip == null) {
      FileInputStream in = new FileInputStream(file);
      v.add(doImport(in, fileName, user));
    } else {
      Enumeration entries = zip.entries();
      while (entries.hasMoreElements()) {
        ZipEntry entry = (ZipEntry) entries.nextElement();
        v.add(doImport(zip.getInputStream(entry), fileName + "/"
            + entry.getName(), user));
      }
    }

    return v;
  }

  /**
   * @param in
   * @param streamId
   *          该stream的字符型标识, 日志和返回值中使用该标识.
   * @return vector of ImpexStatus
   * @throws Exception
   */
  public ImpexLog doImport(InputStream rin, String fileName, IUser user)
      throws Exception {
    if (user == null) {
      throw new ParameterException("必须的参数user不能为null");
    }
    Logger logger = Logger.getLogger(ImpexXml.class);
    ImpexMgr impexMgr = ImpexMgr.getInstance();
    InputStream in = rin.markSupported() ? rin : new BufferedInputStream(rin);
    // 读入256个字节, 寻找数据对象: objectName="*"或<objectName>*</objectName>
    byte[] b = new byte[256];
    in.mark(b.length);
    in.read(b);
    in.reset();
    String s = new String(b);
    String objectName = getObjectName(s);
    if (objectName == null) {
      Indicator ind = impexMgr.getIndicator(user.getDomain(), "错误",
          Indicator.IMPORT, user.getDomain(), true);
      ImpexLog log = impexMgr.createImpexLog(ind, user);
      log.setFileName(fileName);
      log.setDescription("不认识的数据包");
      log.addMessage(log.getDescription());
      impexMgr.saveImpexLogT(log);
      return log;
    }

    String impexClassName = CLASSPACKAGE + objectName.toLowerCase() + "."
        + objectName + CLASSSUFFIX;
    logger.debug("数据包" + fileName + "中发现对象" + objectName + ", 调用"
        + impexClassName);
    Indicator ind = impexMgr.getIndicator(user.getDomain(), objectName,
        Indicator.IMPORT, user.getDomain(), true);
    ImpexLog log = impexMgr.createImpexLog(ind, user);

    // 创建处理类com.hd123.rumba.impex.对象名Impex, 执行导入
    IImpexActor impex = null;
    try {
      impex = (IImpexActor) Class.forName(impexClassName).newInstance();
    } catch (ClassNotFoundException e) {
      String msg = "找不到处理类" + impexClassName;
      logger.error(msg);
      log.setDescription(msg);
      log.addMessage(msg);
      impexMgr.saveImpexLogT(log);
      return log;
    }

    log.setFileName(fileName);
    Transaction tx = null;
    try {
      tx = getSession().beginTransaction();
      log = impex.importFromStream(in, log);
      tx.commit();
    } catch (Exception e) {
      if (tx != null)
        tx.rollback();
      log.setDescription(e.getMessage());
      log.addMessage(e.getMessage());
      Logger.getLogger(this.getClass()).error(e.getMessage());
    }

    log.setEndTime(new Date());
    log.setCommitTime(log.getEndTime());
    log.setState(ImpexLog.COMMITED);
    impexMgr.saveImpexLogT(log);

    return log;
  }

  private String getObjectName(String s) {
    int ib0, ib1, ie;
    String lead = LEAD, end = END;
    ib0 = s.indexOf(LEAD);
    if (ib0 < 0) {
      ib0 = s.indexOf(LEAD2);
      lead = LEAD2;
      end = END2;
    }
    if (ib0 < 0)
      return null;
    ib1 = ib0 + lead.length();
    ie = s.indexOf(end, ib1);
    return s.substring(ib1, ie);
  }

  public ImpexLog doExport(String objectName, OutputStream out, IUser user)
      throws Exception {
    ImpexMgr impexMgr = ImpexMgr.getInstance();
    Logger logger = Logger.getLogger(this.getClass());
    Indicator ind = impexMgr.getIndicator(user.getDomain(), objectName,
        Indicator.EXPORT, user.getDomain(), true);
    String impexClassName = CLASSPACKAGE + objectName.toLowerCase() + "."
        + objectName + CLASSSUFFIX;
    ImpexLog log = impexMgr.createImpexLog(ind, user);
    log.setFileName(objectName);
    IImpexActor impex = null;
    try {
      impex = (IImpexActor) Class.forName(impexClassName).newInstance();
    } catch (ClassNotFoundException e) {
      log.setDescription("找不到处理类" + impexClassName);
      logger.error(log.getDescription());
      impexMgr.saveImpexLog(log);
      return log;
    }
    logger.debug("导出" + objectName + ", 使用类" + impexClassName);
    log.setCurrentExportCondition(null); // 导出全部内容
    log = impex.exportToStream(out, log);
    log.setState(ImpexLog.COMMITED);
    log.setCommitTime(new Date());
    impexMgr.saveImpexLogT(log);
    return log;
  }

  public ImpexLog doExport(String objectName, File file, IUser user)
      throws Exception {
    FileOutputStream out = new FileOutputStream(file);
    ImpexLog log = null;
    try {
      log = doExport(objectName, out, user);
    } finally {
      if (out != null) {
        out.flush();
        out.close();
      }
    }
    return log;
  }
}
